home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 115 / macaddict115.cdr / Software / Development / phpstudio.dmg / PHP Studio.app / Contents / Frameworks / ThreadWorker.h < prev   
Text File  |  2005-12-17  |  9KB  |  259 lines

  1. #import <Cocoa/Cocoa.h>
  2.  
  3.  
  4. /*!
  5. @class ThreadWorker
  6. @abstract v0.7 - Throws a task onto another thread and notifies you when it's done.
  7. @discussion
  8.  
  9. Usage:
  10. <pre>
  11. [ThreadWorker 
  12.         workOn:self 
  13.   withSelector:@selector(longTask:) 
  14.     withObject:someData
  15. didEndSelector:@selector(longTaskFinished:) ];
  16. </pre>
  17. The ThreadWorker class was designed to be simple and
  18. to make multi-threading even simpler. You can offload
  19. tasks to another thread and be notified when the task
  20. is finished.
  21.  
  22. In this sense it is similar to the Java SwingWorker
  23. class, though the need for such a class in Cocoa
  24. and Objective-C is as different as the implementation.
  25.  
  26. Be sure to copy the ThreadWorker.h and ThreadWorker.m
  27. files to your project directory.
  28.  
  29. To see how to use this class, see the documentation for
  30. the "workOn" method below.
  31.  
  32. I recommend registering at the link below to let
  33. SourceForge contact you when new versions of ThreadWorker
  34. are released:
  35.  
  36. <a href="http://sourceforge.net/project/filemodule_monitor.php?filemodule_id=24102">http://sourceforge.net/project/filemodule_monitor.php?filemodule_id=24102</a>
  37.  
  38. I'm releasing this code into the Public Domain.
  39. Do with it as you will. Enjoy!
  40.  
  41. Original author: Robert Harder, rob@iharder.net
  42.  
  43.  
  44. Change History
  45.  
  46. <pre>
  47. 0.7 -
  48.  o  Added ability to mark thread as cancelled.
  49.  o  Changed the behavior when "longTask" takes a second argument.
  50.     Instead of passing a proxy to the primary thread's "self"
  51.     it passes a references to the ThreadWorker. The recommended way
  52.     to pass information from the primary, or originating, thread
  53.     is to use an NSDictionary to pass in the Things You'll Need.
  54.     See the Controller.m example.
  55.  o  Changed thread's termination behavior so that as soon as your
  56.     "longTask:" is finished, the thread will exit. This means if
  57.     you left anything on the NSRunLoop (or more likely an NSURL
  58.     did it without your knowledge), it will get dumped.
  59.  
  60. 0.6.2 - Moved [super dealloc] to the end of the dealloc method and
  61. ensured "init" returns nil if it fails.
  62.  
  63. 0.6.1 - Added [super dealloc] to the dealloc method and moved the
  64. dealloc declaration out of the private API and into the
  65. public .h file as it should be.
  66.  
  67. 0.6 - Eliminated the need for the runSelectorInCallingThread method
  68. by making a proxy to the target available to the task working
  69. in the new thread. This makes for much less overhead.
  70. Also changed static method signature from withArgument to withObject.
  71.  
  72. 0.5.1 - Oops. Forget a necessary thread lock for the NSConnection creation.
  73.  
  74. 0.5 - Uses NSConnection to communicate between threads, so although we
  75. might have been thread-safe before (depending on whether or not
  76. addTimer in NSRunLoop is thread-safe), we're definitely thread-safe
  77. now - or so we think. =)
  78. In the process we had to do away with the helper functions that took
  79. a bit of hassle out using runSelectorInCallingThread with arguments
  80. that are not objects. Sorry.
  81.  
  82. 0.4.1 - Fixed some typos in commented sections.
  83.  
  84. 0.4 - Released into the Public Domain. Enjoy!
  85.  
  86. 0.3 - Permitted "workOn" method to accept a second argument of type
  87. ThreadWorker* to allow for passing of the parent ThreadWorker
  88. to the secondary thread. This makes it easy and reliable to
  89. call other methods on the calling thread.
  90.  
  91. 0.2 - Added runSelectorInCallingThread so that you could make calls
  92. back to the main, i.e. calling, thread from the secondary thread.
  93.  
  94. 0.1 - Initial release.
  95. </pre>
  96. */
  97. @interface ThreadWorker : NSObject
  98. {
  99.    id               _target;            // The object whose selector will be called
  100.    SEL              _selector;          // The selector that will be called in another thread
  101.    id               _argument;          // The argument that will be passed to the selector
  102.    SEL              _didEndSelector;    // Selector for final notice
  103.    NSConnection    *_callingConnection; // Connection used to safely communicate between threads
  104.    NSPort          *_port1;
  105.    NSPort          *_port2;
  106.    NSConnection    *_conn2;
  107.    NSConditionLock *_cancelled;
  108.    BOOL                _endRunLoop;
  109. }
  110.  
  111.  
  112.  
  113. /*!
  114. @method workOn:withSelector:withObject:didEndSelector:
  115. @param target The object to receive the selector message. It is retained.
  116. @param selector The selector to be called on the target in the worker thread.
  117. @param userInfo An optional argument if you wish to pass one to the selector
  118.        and target. It is retained.
  119. @param didEndSelector An optional selector to call on the target. Use the
  120.        value 0 (zero) if you don't want a selector called at the end.
  121. @result Returns an autoreleased ThreadWorker that manages the worker thread.
  122.  
  123. @abstract Call this class method to work on something in another thread. 
  124. @discussion
  125.  
  126. Example:
  127.  <pre>
  128.     NSDictionary *thingsIllNeed = [NSDictionary dictionaryWithObjectsAndKeys:
  129.        self, @"self",
  130.        myProgressIndicator, @"progress",
  131.        myStatusField, @"status", nil];
  132.  
  133.     [ThreadWorker workOn:self 
  134.                   withSelector:@selector(longTask:) 
  135.                   withObject:thingsIllNeed
  136.                   didEndSelector:@selector(longTaskFinished:)];
  137.  </pre>
  138.  
  139. The longTask method in self will then be called and should look
  140. something like this:
  141.  <pre>
  142.     - (id)longTask:(id)userInfo
  143.     {
  144.         // Do something that takes a while and uses 'userInfo' if you want
  145.         id otherSelf = [userInfo objectForKey:@"self"];
  146.             NSProgressIndicator *progress =
  147.             (NSProgressIndicator *)[userInfo objectForKey:@"progress"];
  148.             NSTextField *status =
  149.             (NSTextField *)[userInfo objectForKey:@"status"];
  150.  
  151.         return userInfo; // Will be passed to didEndSelector
  152.     }    
  153.  </pre>
  154. Optionally you can have this "longTask" method accept a second argument
  155. which will be the controlling ThreadWorker instance which you can use
  156. to see if the ThreadWorker has been marked as cancelled.
  157. Your "longTask" method might then look like this:
  158.  <pre>
  159.     - (id)longTask:(id)userInfo anyNameHere:(ThreadWorker *)tw
  160.    {
  161.        ...
  162.        while(... && ![tw cancelled]){
  163.            ...
  164.        }
  165.    }
  166.  </pre>
  167. You can name the second parameter anythign you want. You only have to
  168. match it when you create the ThreadWorker like so:
  169.  <pre>
  170.     [ThreadWorker workOn:self 
  171.                   withSelector:@selector(longTask: anyNameHere:) 
  172.                   withObject:userInfo
  173.                   didEndSelector:@selector(longTaskFinished:)];
  174.  
  175.  </pre>
  176. When your longTask method is finished, whatever is returned from it will
  177. be passed to the didEndSelector (if it's not nil) as that selector's
  178. only argument. The didEndSelector will be called on the original thread,
  179. so if you launched the thread as a result of a user clicking on something,
  180. the longTaskFinished will be called on the main thread, which is what you
  181. need if you want to then modify any GUI components.
  182. The longTaskFinished method might look something like this, then:
  183.  <pre>
  184.     - (void)longTaskFinished:(id)userInfo
  185.     {
  186.         //Do something now that the thread is done
  187.         // ...
  188.     }    
  189.  </pre>
  190. Of course you will have to have imported the ThreadWorker.h
  191. file in your class's header file. The top of your header file
  192. might then look like this:
  193.  <pre>
  194.     import <Cocoa/Cocoa.h>
  195.     import "ThreadWorker.h"
  196.  </pre>
  197. Enjoy.
  198.  
  199.  */
  200. + (ThreadWorker *)
  201.     workOn:(id)target 
  202.     withSelector:(SEL)selector 
  203.     withObject:(id)userInfo
  204.     didEndSelector:(SEL)didEndSelector;
  205.  
  206.  
  207.     /*!
  208.      @method markAsCancelled
  209.      @abstract Mark the ThreadWorker as cancelled.
  210.      @discussion
  211.      Marks the ThreadWorker as cancelled but doesn't actually
  212.      cancel the thread. It is up to you to check whether or
  213.      not the ThreadWorker is cancelled using a two-argument
  214.      "longTask:..." method like so:
  215. <pre>
  216.      - (id)longTask:(id)userInfo anyNameHere:(ThreadWorker *)tw
  217.      {
  218.          ...
  219.          while(... && ![tw cancelled]){
  220.              ...
  221.          }
  222.      }
  223. </pre>
  224.      */
  225. -(void)markAsCancelled;
  226.  
  227.  
  228.     /*!
  229.      @method cancelled
  230.      @abstract Returns whether or not someone has tried to cancel the thread.
  231.      @discussion Returns whether or not someone has tried to cancel the thread.
  232.      */
  233. -(BOOL)cancelled;
  234.  
  235.  
  236.  
  237.     /*!
  238.     @method dealloc
  239.     @abstract Make sure we clean up after ourselves.
  240.     @discussion Make sure we clean up after ourselves.
  241.     */
  242. - (void) dealloc;
  243.  
  244.  
  245.     /*!
  246.     @method description
  247.      @abstract Just a little note to say, "Good job, Rob!"
  248.      @discussion
  249.      Just a little note to say, "Good job, Rob!" to
  250.      the original author of this Public Domain software.
  251.      */
  252. + (NSString *)description;
  253.  
  254.  
  255.  
  256.  
  257. @end
  258.  
  259.